
/**
  ******************************************************************************
  * Copyright 2021 The grapilot Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       gp_serial.c
  * @author     baiyang
  * @date       2021-7-15
  ******************************************************************************
  */

/*----------------------------------include-----------------------------------*/
#include <stdint.h>
#include "gp_serial_device.h"
#include "gp_serial.h"
#include <common/console/console.h>
#include <parameter/param.h>
/*-----------------------------------macro------------------------------------*/

/*----------------------------------typedef-----------------------------------*/
struct gp_serial_device serials[8];
/*---------------------------------prototype----------------------------------*/

/*----------------------------------variable----------------------------------*/

/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
/*
 *  map from a 16 bit EEPROM baud rate to a real baud rate.  For
 *  stm32-based boards we can do 1.5MBit, although 921600 is more
 *  reliable.
 */
uint32_t gp_serial_map_baudrate(int32_t rate)
{
    if (rate <= 0) {
        rate = 57;
    }
    switch (rate) {
    case 1:    return 1200;
    case 2:    return 2400;
    case 4:    return 4800;
    case 9:    return 9600;
    case 19:   return 19200;
    case 38:   return 38400;
    case 57:   return 57600;
    case 100:  return 100000;
    case 111:  return 111100;
    case 115:  return 115200;
    case 230:  return 230400;
    case 256:  return 256000;
    case 460:  return 460800;
    case 500:  return 500000;
    case 921:  return 921600;
    case 1500:  return 1500000;
    }

    if (rate > 2000) {
        // assume it is a direct baudrate. This allows for users to
        // set an exact baudrate as long as it is over 2000 baud
        return (uint32_t)rate;
    }

    // otherwise allow any other kbaud rate
    return rate*1000;
}

/**
  * @brief       seirla分配对应的功能号
  * @param[in]   
  * @param[out]  
  * @retval      
  * @note        
  */
static void gp_serial_assign(void)
{
    serials[0].protocol = PARAM_GET_INT8(SERIAL, SERIAL1_PROTOCOL);
    serials[0].baud = gp_serial_map_baudrate(PARAM_GET_INT32(SERIAL, SERIAL1_BAUD));

    serials[1].protocol = PARAM_GET_INT8(SERIAL, SERIAL2_PROTOCOL);
    serials[1].baud = gp_serial_map_baudrate(PARAM_GET_INT32(SERIAL, SERIAL2_BAUD));

    serials[2].protocol = PARAM_GET_INT8(SERIAL, SERIAL3_PROTOCOL); 
    serials[2].baud = gp_serial_map_baudrate(PARAM_GET_INT32(SERIAL, SERIAL3_BAUD));

    serials[3].protocol = PARAM_GET_INT8(SERIAL, SERIAL4_PROTOCOL);
    serials[3].baud = gp_serial_map_baudrate(PARAM_GET_INT32(SERIAL, SERIAL4_BAUD));

    serials[4].protocol = PARAM_GET_INT8(SERIAL, SERIAL5_PROTOCOL);
    serials[4].baud = gp_serial_map_baudrate(PARAM_GET_INT32(SERIAL, SERIAL5_BAUD));

    serials[5].protocol = PARAM_GET_INT8(SERIAL, SERIAL6_PROTOCOL);
    serials[5].baud = gp_serial_map_baudrate(PARAM_GET_INT32(SERIAL, SERIAL6_BAUD));

    serials[6].protocol = PARAM_GET_INT8(SERIAL, SERIAL7_PROTOCOL);
    serials[6].baud = gp_serial_map_baudrate(PARAM_GET_INT32(SERIAL, SERIAL7_BAUD));

    serials[7].protocol = PARAM_GET_INT8(SERIAL, SERIAL8_PROTOCOL);
    serials[7].baud = gp_serial_map_baudrate(PARAM_GET_INT32(SERIAL, SERIAL8_BAUD));
}
/**
  * @brief       将serial设备和uart设备一一对应，并将serial设备赋予功能
  * @param[in]   device:serial设备
  * @param[out]  
  * @retval      
  * @note        
  */
void gp_serial_device_init (void)
{
    gp_serial_assign();
#ifdef GP_SERIAL1_DEVICE_NAME
    serials[0].pname = "serial1";
    serials[0].puart = rt_device_find(GP_SERIAL1_DEVICE_NAME);  //serial[0]对应serial1,所对应的uart由menuconfig用户配置
#ifdef GP_SERIAL1_TX_USING_DMA
    serials[0].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_TX;
#else
    serials[0].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_TX;
#endif
#ifdef GP_SERIAL1_RX_USING_DMA
    serials[0].oflag |= RT_DEVICE_FLAG_DMA_RX;
#else
    serials[0].oflag |= RT_DEVICE_FLAG_INT_RX;
#endif
#endif

#ifdef GP_SERIAL2_DEVICE_NAME
    serials[1].pname = "serial2";
    serials[1].puart = rt_device_find(GP_SERIAL2_DEVICE_NAME);
#ifdef GP_SERIAL2_TX_USING_DMA
    serials[1].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_TX;
#else
    serials[1].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_TX;
#endif
#ifdef GP_SERIAL2_RX_USING_DMA
    serials[1].oflag |= RT_DEVICE_FLAG_DMA_RX;
#else
    serials[1].oflag |= RT_DEVICE_FLAG_INT_RX;
#endif
#endif

#ifdef GP_SERIAL3_DEVICE_NAME
    serials[2].pname = "serial3";
    serials[2].puart = rt_device_find(GP_SERIAL3_DEVICE_NAME);
#ifdef GP_SERIAL3_TX_USING_DMA
    serials[2].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_TX;
#else
    serials[2].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_TX;
#endif
#ifdef GP_SERIAL3_RX_USING_DMA
    serials[2].oflag |= RT_DEVICE_FLAG_DMA_RX;
#else
    serials[2].oflag |= RT_DEVICE_FLAG_INT_RX;
#endif
#endif

#ifdef GP_SERIAL4_DEVICE_NAME
    serials[3].pname = "serial4";
    serials[3].puart = rt_device_find(GP_SERIAL4_DEVICE_NAME);
#ifdef GP_SERIAL4_TX_USING_DMA
    serials[3].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_TX;
#else
    serials[3].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_TX;
#endif
#ifdef GP_SERIAL4_RX_USING_DMA
    serials[3].oflag |= RT_DEVICE_FLAG_DMA_RX;
#else
    serials[3].oflag |= RT_DEVICE_FLAG_INT_RX;
#endif
#endif

#ifdef GP_SERIAL5_DEVICE_NAME
    serials[4].pname = "serial5";
    serials[4].puart = rt_device_find(GP_SERIAL5_DEVICE_NAME);
#ifdef GP_SERIAL5_TX_USING_DMA
    serials[4].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_TX;
#else
    serials[4].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_TX;
#endif
#ifdef GP_SERIAL5_RX_USING_DMA
    serials[4].oflag |= RT_DEVICE_FLAG_DMA_RX;
#else
    serials[4].oflag |= RT_DEVICE_FLAG_INT_RX;
#endif
#endif

#ifdef GP_SERIAL6_DEVICE_NAME
    serials[5].pname = "serial6";
    serials[5].puart = rt_device_find(GP_SERIAL6_DEVICE_NAME);
#ifdef GP_SERIAL6_TX_USING_DMA
    serials[5].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_TX;
#else
    serials[5].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_TX;
#endif
#ifdef GP_SERIAL6_RX_USING_DMA
    serials[5].oflag |= RT_DEVICE_FLAG_DMA_RX;
#else
    serials[5].oflag |= RT_DEVICE_FLAG_INT_RX;
#endif
#endif

#ifdef GP_SERIAL7_DEVICE_NAME
    serials[6].pname = "serial7";
    serials[6].puart = rt_device_find(GP_SERIAL7_DEVICE_NAME);
#ifdef GP_SERIAL7_TX_USING_DMA
    serials[6].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_TX;
#else
    serials[6].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_TX;
#endif
#ifdef GP_SERIAL7_RX_USING_DMA
    serials[6].oflag |= RT_DEVICE_FLAG_DMA_RX;
#else
    serials[6].oflag |= RT_DEVICE_FLAG_INT_RX;
#endif
#endif

#ifdef GP_SERIAL8_DEVICE_NAME
    serials[7].pname = "serial8";
    serials[7].puart = rt_device_find(GP_SERIAL8_DEVICE_NAME);
#ifdef GP_SERIAL8_TX_USING_DMA
    serials[7].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_TX;
#else
    serials[7].oflag = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_TX;
#endif
#ifdef GP_SERIAL8_RX_USING_DMA
    serials[7].oflag |= RT_DEVICE_FLAG_DMA_RX;
#else
    serials[7].oflag |= RT_DEVICE_FLAG_INT_RX;
#endif
#endif

    for(uint8_t i = 0; i < 8; i++)
    {
        if(serials[i].puart != NULL)
        {
            switch(serials[i].protocol)
            {
                case SerialProtocol_GPS:
                    serials[i].rb_tx = rt_ringbuffer_create(GP_SERIAL_GPS_BUFSIZE_TX);
                    serials[i].rb_rx = rt_ringbuffer_create(GP_SERIAL_GPS_BUFSIZE_RX);
                    break;

                case SerialProtocol_MAVLink2:
                    serials[i].rb_tx = rt_ringbuffer_create(GP_SERIAL_MAV_BUFSIZE_TX);
                    serials[i].rb_rx = rt_ringbuffer_create(GP_SERIAL_MAV_BUFSIZE_RX);
                    break;

                default:
                    serials[i].rb_tx = rt_ringbuffer_create(GP_SERIAL_DEFAULT_BUFSIZE_TX);
                    serials[i].rb_rx = rt_ringbuffer_create(GP_SERIAL_DEFAULT_BUFSIZE_RX);
                    break;
            }

            gp_serial_device_register(&serials[i], serials[i].pname, RT_DEVICE_FLAG_RDWR);

            // 在这里打开串口，线程中打开串口，因为线程优先级的问题，有可能其他高优先级的
            // 线程会使用没有打开的串口，造成死循环
            rt_device_open((rt_device_t)&serials[i], RT_NULL); //oflag无用，通过宏配置
        }
    }
}

/**
  * @brief       根据功能号查找serial设备
  * @param[in]   protocol  功能
  * @param[out]                                
  * @retval      
  * @note        
  */
rt_device_t SerialManager_find_protocol(SerialProtocol protocol)
{
    for(uint8_t i = 0; i < 8; i++)
    {
        if(serials[i].protocol == protocol)
        {
            return &serials[i].parent;
        }
    }
    console_printf("No assigned serial found\n");
    return RT_NULL;
}

/**
  * @brief       返回对应功能号串口的波特率
  * @param[in]   protocol  
  * @param[out]  
  * @retval      
  * @note        
  */
uint32_t SerialManager_find_baudrate(SerialProtocol protocol)
{
    gp_serial_device_t seri = (gp_serial_device_t)SerialManager_find_protocol(protocol);

    if (seri == NULL) {
        return 0;
    }

    return seri->baud;
}

/**
  * @brief       设置串口波特率
  * @param[in]   pSerial  
  * @param[in]   baudrate  
  * @param[out]  
  * @retval      
  * @note        
  */
int32_t SerialManager_set_baudrate(rt_device_t pSerial, uint32_t baudrate)
{
    int32_t err = 0;
    struct serial_configure conf = RT_SERIAL_CONFIG_DEFAULT;
    conf.baud_rate = baudrate;

    err = rt_device_control(pSerial, RT_DEVICE_CTRL_CONFIG, &conf);

    return err;
}

/**
  * @brief       计算接受缓冲区接收到数据的大小
  * @param[in]   pSerial  
  * @param[out]  
  * @retval      
  * @note        
  */
int16_t SerialManager_rx_available(rt_device_t pSerial)
{
    if (pSerial == NULL) {
        return -1;
    }

    gp_serial_device_t pSeri = (gp_serial_device_t)pSerial;

    return rt_ringbuffer_data_len(pSeri->rb_rx);
}

/**
  * @brief       计算发送缓冲区剩余大小
  * @param[in]   pSerial  
  * @param[out]  
  * @retval      
  * @note        
  */
int16_t SerialManager_tx_space(rt_device_t pSerial)
{
    if (pSerial == NULL) {
        return -1;
    }

    gp_serial_device_t pSeri = (gp_serial_device_t)pSerial;

    return (pSeri->rb_tx->buffer_size - rt_ringbuffer_data_len(pSeri->rb_tx));
}

/*------------------------------------test------------------------------------*/


